import { AudioOutlined, SendOutlined, SoundOutlined } from "@ant-design/icons";
import { Button } from "antd";
import React from "react";

const getMediaRecorder = () =>
  new Promise<MediaRecorder>((resolve, reject) => {
    if (navigator.mediaDevices.getUserMedia) {
      const constraints: MediaStreamConstraints = { audio: true };
      navigator.mediaDevices.getUserMedia(constraints).then(
        (stream) => {
          resolve(new MediaRecorder(stream));
        },
        (e) => {
          console.error("授权失败", e);
          reject(new Error("授权失败"));
        },
      );
    } else {
      reject(new Error("浏览器不支持 getUserMedia"));
    }
  });

type Props = {
  onFinish?: (b: Blob) => void;
  onStart?: () => void;
  stage: "init" | "voice" | "speek";
};

// TODO: 出错的回调
export default class VoiceRecorder extends React.Component<Props> {
  private mediaRecorder: MediaRecorder | null;
  private chunks: Blob[];

  constructor(props: Props) {
    super(props);
    this.mediaRecorder = null;
    this.chunks = [];
  }

  handleMRStop = () => {
    this.setState({ recording: false });
    const blob = new Blob(this.chunks, { type: "audio/ogg; codecs=opus" });
    this.props.onFinish?.(blob);
    this.chunks = [];
  };

  handleStart = async () => {
    try {
      if (this.mediaRecorder == null) {
        this.mediaRecorder = await getMediaRecorder();
        this.mediaRecorder.ondataavailable = (e) => {
          console.log("voice recorder: data received");
          this.chunks.push(e.data);
        };
        this.mediaRecorder.onstop = () => {
          console.log("voice recorder: stopped");
          this.handleMRStop();
        };
      }

      const { state } = this.mediaRecorder;
      if (state === "inactive") {
        this.mediaRecorder.start();
        this.props.onStart?.();
      }
      this.setState({ recording: true });
    } catch (e) {
      alert((e as Error).message);
    }
  };

  handlePause = () => {
    this.mediaRecorder?.pause();
  };

  handleStop = () => {
    this.mediaRecorder?.stop();
  };

  render() {
    const { stage } = this.props;
    return (
      <div className="flex gap-4">
        {(() => {
          switch (stage) {
            case "init":
              return (
                <Button
                  shape="circle"
                  type="primary"
                  onClick={this.handleStart}
                  icon={<AudioOutlined />}
                />
              );
            case "voice":
              return (
                <Button
                  onClick={this.handleStop}
                  shape="circle"
                  icon={<SendOutlined />}
                />
              );
            case "speek":
              return (
                <Button shape="circle" disabled icon={<SoundOutlined />} />
              );
            default:
              throw new Error(`unsupported stage: ${stage}`);
          }
        })()}
      </div>
    );
  }
}
